
/**
 * Bunny Bounce (tentitive title)
 * @author Billy Monks, Alec Fisher-Lasky, Nick Kitten
 *
 * Contains snipets of code from Tim Wright's article on Active Rendering in Java
 * http://www.gamedev.net/reference/articles/article2418.asp
 */
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.*;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;


//public class Main extends JFrame implements Runnable, KeyListener {
public class Main extends JFrame implements KeyListener, MouseListener {

    private static boolean running;
    private static boolean[] keys = new boolean[4]; //LEFT,RIGHT,UP,DOWN

    // Variables for keeping track of mouse presses/launching
    private static long timePressed;
    private static int launchX, launchY;
    private static float vX = 0;
    private static float vY = 0;
    private static float launchPower = 0;
    private static float launchDist = 0;
    private static boolean crouching, launched;

    // projectile motion constants
    private static final float GRAVITY = 2;
    private static final long MAX_PRESS_TIME = 500;
    private static final float LAUNCH_VELOCITY = 40;
    private static final float MIN_SPEED = (float).5;
    private static final float MAX_SPEED = 20;

    public static ArrayList<Entity> entityList;
    private static Entity bunny;

    public Main() {
        super();
        addKeyListener(this);
        addMouseListener(this);
    }

    public static void main(String[] args) {
        Resources r = new Resources();
        Main app = new Main();
        app.setIgnoreRepaint(true);
        app.setUndecorated(true);


        // Get graphics configuration...
        GraphicsEnvironment ge =
                GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        GraphicsConfiguration gc = gd.getDefaultConfiguration();

        // Change to full screen
        gd.setFullScreenWindow(app);
        if (gd.isDisplayChangeSupported()) {
            gd.setDisplayMode(
                    new DisplayMode(640, 480, 32, 60)); // Implement letting player change resolution
        }

        // Create BackBuffer...
        app.createBufferStrategy(2);
        BufferStrategy buffer = app.getBufferStrategy();

        // Create off-screen drawing surface
        BufferedImage bi = gc.createCompatibleImage(640, 480);

        // Objects needed for rendering...
        Graphics graphics = null;
        Graphics2D g2d = null;
        Color background = Color.BLACK;
        Random rand = new Random();

        // Variables for counting frames per seconds
        int fps = 0;
        int frames = 0;
        long totalTime = 0;
        long curTime = System.currentTimeMillis();
        long lastTime = curTime;
        running = true;


        entityList = new ArrayList<Entity>();

        bunny = new Entity("bunny", 100, 100, r.bunnyStill);

        while (running) {
            try {
                // count Frames per second...
                lastTime = curTime;
                curTime = System.currentTimeMillis();
                totalTime += curTime - lastTime;
                if (totalTime > 1000) {
                    totalTime -= 1000;
                    fps = frames;
                    frames = 0;
                }
                ++frames;
                run();

                // clear back buffer...
                g2d = bi.createGraphics();
                g2d.setColor(background);
                g2d.fillRect(0, 0, 639, 479);

                // draw to screen here:
                for (int i = 0; i < entityList.size(); ++i) {
                    g2d.drawImage(entityList.get(i).getImage(), entityList.get(i).getX(), entityList.get(i).getY(), app);
                }


                // display frames per second...
                g2d.setFont(new Font("Courier New", Font.PLAIN, 12));
                g2d.setColor(Color.GREEN);
                g2d.drawString(String.format("FPS: %s", fps), 20, 20);

                // Blit image and flip...
                graphics = buffer.getDrawGraphics();
                graphics.drawImage(bi, 0, 0, null);

                if (!buffer.contentsLost()) {
                    buffer.show();
                }

            } finally {
                // release resources
                if (graphics != null) {
                    graphics.dispose();
                }
                if (g2d != null) {
                    g2d.dispose();
                }
            }
        }

        gd.setFullScreenWindow(null);
        System.exit(0);

    }

    public void keyTyped(KeyEvent e) {
    }

    public void keyPressed(KeyEvent e) {
        keyDown(e);
    }

    public void keyReleased(KeyEvent e) {
        keyUp(e);
    }

    private int getKeyCode(KeyEvent e) {
        return (e.getKeyCode());
    }

    private void keyDown(KeyEvent e) {

        switch (e.getKeyCode()) {

            case 27: //ESC
                running = false;
                break;

            case 37: //LEFT
                keys[0] = true;
                break;

            case 39: //RIGHT
                keys[1] = true;
                break;

            case 38: //UP
                keys[2] = true;
                break;

            case 40: //DOWN
                keys[3] = true;
                break;

            default:
                //System.out.println(e.getKeyCode()); // Uncomment to test keys.
                break;
        }
    }

    private void keyUp(KeyEvent e) {
        switch (e.getKeyCode()) {
            case 37: //LEFT
                keys[0] = false;
                break;

            case 39: //RIGHT
                keys[1] = false;
                break;

            case 38: //UP
                keys[2] = false;
                break;

            case 40: //DOWN
                keys[3] = false;
                break;

            default:
                break;
        }
    }

    public void mousePressed(MouseEvent e) {
        if (e.getButton() == e.BUTTON1 && !launched) {
            timePressed = System.currentTimeMillis();
            crouching = true;
        }
    }

    public void mouseReleased(MouseEvent e){
        if (e.getButton() == e.BUTTON1 && !launched) {
            timePressed = System.currentTimeMillis() - timePressed;
            crouching = false;
            launched = true;
            launchX = e.getX() - bunny.getX();
            launchY = Math.min(0, e.getY() - bunny.getY());
            launchDist = (float)Math.sqrt(launchX * launchX + launchY * launchY);
            launchPower = (float)Math.min(timePressed,MAX_PRESS_TIME) / MAX_PRESS_TIME;
            launchPower = (float)Math.cbrt(launchPower) * LAUNCH_VELOCITY;
            vX = launchX / launchDist * launchPower;
            vY = launchY / launchDist * launchPower;
        }
    }

    public void mouseExited(MouseEvent e){
    }

    public void mouseClicked(MouseEvent e){

    }

    public void mouseEntered(MouseEvent e){

    }

    private static void run() {
        if(crouching){
            vX *= .9;
            if(Math.abs(vX) < MIN_SPEED){
                vX = 0;
            }

        }
        else if(launched){
            vY += GRAVITY;
            vY = Math.min(vY, MAX_SPEED);
            if(bunny.getY() + vY > 445){
                launched = false;
                vY = 440 - bunny.getY();
            }
        }
        else if (keys[0] == true && keys[1] == false) {
            vX -= 1;
            vX = Math.max(-MAX_SPEED, vX);
        } else if (keys[0] == false && keys[1] == true) {
            vX += 1;
            vX = Math.min(MAX_SPEED, vX);
        }
        else{
            vX *= .8;
            vY = 0;
        }
        bunny.setX(bunny.getX() + (int)vX);
        bunny.setY(bunny.getY() + (int)vY);
    }
}
